package com.miao.test.client;

import cn.hutool.extra.spring.SpringUtil;
import com.miao.test.common.Message;
import com.miao.test.common.enums.Command;
import com.miao.test.model.AuthResponseModel;
import com.miao.test.model.HeartBeatModel;
import com.miao.test.support.ProtoBufUtil;
import com.miao.test.support.SocketUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: miaoguoxin
 * @Date: 2021/5/14 17:17
 * @Description:
 */
@Slf4j
public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {

    public static Map<Channel, AuthResponseModel.AuthResponse> userInfos = new ConcurrentHashMap<>();
    private WebSocketClientHandshaker handshaker = null;
    private ChannelPromise handshakeFuture = null;

    public void handlerAdded(ChannelHandlerContext ctx) {
        this.handshakeFuture = ctx.newPromise();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        log.info("连接已激活");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.debug("WebSocketClientHandler::channelRead0: ");

        // 握手协议返回，设置结束握手
        if (!this.handshaker.isHandshakeComplete()) {
            FullHttpResponse response = (FullHttpResponse) msg;
            this.handshaker.finishHandshake(ctx.channel(), response);
            this.handshakeFuture.setSuccess();
            log.debug("WebSocketClientHandler::channelRead0 HandshakeComplete...");
            return;
        }

        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame textFrame = (TextWebSocketFrame) msg;
            log.debug("WebSocketClientHandler::channelRead0 textFrame: " + textFrame.text());
        }

        if (msg instanceof CloseWebSocketFrame) {
            log.debug("WebSocketClientHandler::channelRead0 CloseWebSocketFrame");
        }

        if (msg instanceof BinaryWebSocketFrame) {
            BinaryWebSocketFrame msgBinary = (BinaryWebSocketFrame) msg;
            Message message = Message.read(msgBinary.content());
            Command command = Command.getByCode(message.getCommandType());
            switch (command) {
                case AUTH:
                    userInfos.put(ctx.channel(), ProtoBufUtil.parse(message.getBody(), AuthResponseModel.AuthResponse.class));
                    ClientTest.scheduler.scheduleAtFixedRate(() -> {
                        HeartBeatModel.Heartbeat heartbeat = HeartBeatModel.Heartbeat.newBuilder()
                                .setTimestamp(System.currentTimeMillis())
                                .build();
                        Message writeRequest = Message.writeRequest(1, 0, Command.HEART_BEAT.getCode(), heartbeat.toByteArray());
                        BinaryWebSocketFrame binaryWebSocketFrame = new BinaryWebSocketFrame(writeRequest.getByteBuf());
                        ctx.channel().writeAndFlush(binaryWebSocketFrame);
                    }, 5, 15, TimeUnit.SECONDS);
                    break;
                case GENERATE_ID:
                    log.info("接收到生成id");
                    break;
                case P2P_SENDER:
                    //log.info("收到单聊响应");
                    SocketUtil.SocketListener socketListener = SocketUtil.listenerMap.get(message.getSequence());
                    if (socketListener != null) {
                        socketListener.callback(message);
                    }
                    break;
                case HEART_BEAT:
                case P2P_NOTIFY_TO_SENDER_ACK:
                    //  log.info("收到对端的ack消息");
                    break;
                default:
            }
        }
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//        System.out.println("WebSocketClientHandler::channelInactive 服务端连接成功");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("websocket异常：", cause);
        ctx.channel().close();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.WRITER_IDLE) {
                // write heartbeat to server
                HeartBeatModel.Heartbeat request = HeartBeatModel.Heartbeat.newBuilder()
                        .setTimestamp(System.currentTimeMillis())
                        .build();
                Message writeRequest = Message.writeRequest(1, 0, Command.HEART_BEAT.getCode(), request.toByteArray());
                SpringUtil.getBean(ClientTest.class).sendMsg(writeRequest);
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    public void setHandshaker(WebSocketClientHandshaker handshaker) {
        this.handshaker = handshaker;
    }

    public ChannelFuture handshakeFuture() {
        return this.handshakeFuture;
    }

    public ChannelPromise getHandshakeFuture() {
        return handshakeFuture;
    }

    public void setHandshakeFuture(ChannelPromise handshakeFuture) {
        this.handshakeFuture = handshakeFuture;
    }


}
